package tools

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/spf13/viper"
	"golang.org/x/crypto/bcrypt"
)

/*
 +----------------------------------------------------------------------
 + Title        : 助手函数
 + Author       : huwl
 + Version      : 1.0.0
 + Initial-Time : 2021-09-22
 + Last-time    : 这个文件最后修改的时间 + 修改人的名称
 + Desc         : 助手函数
 +----------------------------------------------------------------------
*/

//时间戳转换日期
func UnixToDate(timestamp int) string {
	return time.Unix(int64(timestamp), 0).Format("2006-01-02 15:04:05")
}

//日期转换时间戳
func DateToUnix(date string) int64 {
	t, err := time.ParseInLocation("2006-01-02 15:04:05", date, time.Local)
	if err != nil {
		return 0
	}

	return t.Unix()
}

//获取时间戳
func GetUnix() int64 {
	return time.Now().Unix()
}

//获取纳秒数
func GetUnixNano() int64 {
	return time.Now().UnixNano()
}

//获取当前日期
func GetDate() string {
	return time.Now().Format("2006-01-02 15:04:05")
}

//获取当前年-月-日
func GetDay() string {
	return time.Now().Format("2006-01-02")
}

//md5加密
func Md5Str(value string) string {
	h := md5.New()
	io.WriteString(h, value)
	return hex.EncodeToString(h.Sum(nil))
}

//bcrypt加密
func Bcrypt(value string) (string, error) {
	hash, err := bcrypt.GenerateFromPassword([]byte(value), bcrypt.DefaultCost)
	return string(hash), err
}

//bcrypt加密对比
func CompareBcrypt(hashValue, value string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(hashValue), []byte(value))
	return err == nil
}

//获取应用路径
func GetAppPath() string {
	file, _ := exec.LookPath(os.Args[0])
	path, _ := filepath.Abs(file)
	index := strings.LastIndex(path, string(os.PathSeparator))

	return path[:index]
}

//获取配置数据
func GetConfig(configName, configType string) (*viper.Viper, error) {
	v := viper.New()
	// v.AddConfigPath(GetAppPath() + "/config/")
	v.AddConfigPath("./config/")
	v.SetConfigName(configName)
	v.SetConfigType(configType)
	err := v.ReadInConfig()
	return v, err
}

// 三目运算的函数
func Ternary(a bool, b, c interface{}) interface{} {
	if a {
		return b
	}
	return c
}

//分割时间2022-08-23T22:56:34+08:00 ----> 2022-08-23 22:56:34
func CutTime(valueStr time.Time) string {
	return valueStr.Format("2006-01-02 15:04:05")
}

func IsContainStr(items []string, item string) bool {
	for _, eachItem := range items {
		if eachItem == item {
			return true
		}
	}
	return false
}

/**
 * 是否包含指定的数字
 *
 * @param []T items -------------------------必传
 * @param T item ---------------------------必传
 * @return bool
 * @author huwl
 */
func IsContainNumber[T uint8 | int8 | uint16 | int16 | uint32 | int32 | uint64 | int64 | uint | int](items []T, item T) bool {
	for _, eachItem := range items {
		if eachItem == item {
			return true
		}
	}
	return false
}

/**
 * 将 [](uint8|int8|uint16|int16|uint32|int32|uint64|int64) 转换为 []int
 *
 * @param []T src ---------------------------必传
 * @return []int
 * @author huwl
 */
func ConvertToInt[T uint8 | int8 | uint16 | int16 | uint32 | int32 | uint64 | int64](src []T) []int {
	dst := make([]int, len(src))
	for i, val := range src {
		dst[i] = int(val)
	}
	return dst
}

//处理两位小数点
func HandleTwoDecimalPoint(value interface{}) string {
	val, ok := value.(string)

	money := ""
	if ok {
		i, _ := strconv.Atoi(val)
		money = strconv.FormatFloat(float64(i)/100, 'f', 2, 64)
	}

	i, ok := value.(int)
	if ok {
		money = strconv.FormatFloat(float64(i)/100, 'f', 2, 64)
	}

	return money
}

//运算
func Operation(n interface{}, operator string, m interface{}) string {
	a, ok := n.(string)

	i := 0
	if ok {
		i, _ = strconv.Atoi(a)
	}

	b, ok := m.(string)
	z := 0
	if ok {
		z, _ = strconv.Atoi(b)
	}

	c, ok := n.(int)

	if ok {
		i = c
	}

	d, ok := m.(int)
	if ok {
		z = d
	}

	result := ""
	switch {
	case operator == "+":
		result = strconv.Itoa(i + z)
	case operator == "-":
		result = strconv.Itoa(i - z)
	case operator == "*":
		result = strconv.Itoa(i * z)
	case operator == "/":
		result = strconv.Itoa(i / z)
	}

	return result
}

//拆分字符串
func StringSplit(value, sep string) []string {
	return strings.Split(value, sep)
}

//字符串转换成html
func StrToHtml(value string) template.HTML {
	return template.HTML(value)
}

//验证手机号
func CheckMobile(mobile string) bool {
	if mobile == "" {
		return false
	}
	pattern := `^1[3|5|7|8|9][\d]{9}$`
	reg := regexp.MustCompile(pattern)
	return reg.MatchString(mobile)
}

/**
 * 删除Proto json omitempty
 *
 * @param string filename ------------------------------------------------------------必传
 * @return template.HTML
 * @author huwl
 */
func RemoveProtoJsonOmitempty(filename string) {
	contents, err := ioutil.ReadFile(filename)
	if err != nil {
		fmt.Println("ioutil ReadFile error：", err.Error())
		return
	}

	data := strings.ReplaceAll(string(contents), ",omitempty", "")
	err = ioutil.WriteFile(filename, []byte(data), 0755)
	if err != nil {
		fmt.Println("ioutil WriteFile error：", err.Error())
		return
	}

	fmt.Println("remove proto json omitempty successfully!!!")
}

/**
 * 分割数字
 *
 * @param string str ----------------------------------------------------必传
 * @param strin delimiter -----------------------------------------------必传
 * @return []int
 * @author huwl
 */
func IntSplit(str string, delimiter string) []int {
	contents := strings.Split(str, delimiter)
	numbers := []int{}
	for _, content := range contents {
		i, _ := strconv.Atoi(content)
		numbers = append(numbers, i)
	}

	return numbers
}

/**
 * 检查目录是否存在，如果不存在则自动创建。
 *
 * @param string logPath ------------------------------------------------必传
 * @return error
 * @author huwl
 */
func EnsureDir(logPath string) error {
	dir := filepath.Dir(logPath)
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		return os.MkdirAll(dir, 0755)
	}

	return nil
}
